package team.seekers.hula.question.question.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.transaction.annotation.Transactional;
import team.seekers.hula.common.entity.PageResult;
import team.seekers.hula.common.entity.VisibilityUpdateDTO;
import team.seekers.hula.common.entity.constant.IdConstant;
import team.seekers.hula.common.entity.enums.MessageTypeEnum;
import team.seekers.hula.common.entity.enums.StatusEnum;
import team.seekers.hula.question.question.entity.vo.QuestionListVO;
import team.seekers.hula.auth.service.MindUtils;
import team.seekers.hula.question.answer.service.AnswerService;
import team.seekers.hula.question.point.service.PointService;
import team.seekers.hula.question.question.entity.dto.QuestionQueryDTO;
import team.seekers.hula.question.question.entity.vo.QuestionHotListVO;
import team.seekers.hula.question.questionUser.service.QuestionUserService;
import team.seekers.hula.record.mind.service.MindService;
import team.seekers.hula.message.message.service.MessageService;
import team.seekers.hula.question.point.entity.dto.PointAddDTO;
import team.seekers.hula.question.question.entity.dto.QuestionAddDTO;
import team.seekers.hula.question.question.entity.vo.QuestionInfoVO;
import team.seekers.hula.question.question.entity.vo.QuestionMindListVO;
import team.seekers.hula.question.question.entity.dto.QuestionUpdateDTO;
import team.seekers.hula.question.question.mapper.QuestionMapper;
import team.seekers.hula.question.answer.entity.dao.AnswerDO;
import team.seekers.hula.question.point.entity.dao.PointDO;
import team.seekers.hula.question.question.entity.dao.QuestionDO;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import team.seekers.hula.message.message.entity.dao.MessageDO;
import team.seekers.hula.user.user.service.UserService;
import team.seekers.hula.user.userData.entity.dao.UserDataDO;
import team.seekers.hula.user.userData.service.UserDataService;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 一个问题服务实现类
 * @author hbc
 * @since 2021-02-15
 */
@Service
public class QuestionService extends ServiceImpl<QuestionMapper, QuestionDO> {

    @Autowired
    @Lazy
    private UserService userService;

    @Autowired
    @Lazy
    private UserDataService userDataService;

    @Autowired
    @Lazy
    private MindService mindService;

    @Autowired
    @Lazy
    private PointService pointService;

    @Autowired
    @Lazy
    private AnswerService answerService;
    @Autowired
    @Lazy
    private MessageService messageService;


    @Resource
    private QuestionUserService questionUserService;


    // 新增问题
    @Transactional(rollbackFor=Exception.class)
    public Map<String,String> add(QuestionAddDTO questionAddDTO) {

        HashMap<String, String> map = new HashMap<>();

        QuestionDO questionDO = new QuestionDO();
        BeanUtils.copyProperties(questionAddDTO, questionDO);

        questionAddDTO.setIsSpecial(questionAddDTO.getIsSpecial());
        questionAddDTO.setIsSpecial(false);

        if(questionAddDTO.getIsSpecial()){
            // 专业提问
            questionDO.setStatus(StatusEnum.WAIT);
            questionDO.setIsSpecial(1);
            // 保存
            save(questionDO);
            // 发送待审核消息
            MessageDO messageDO = new MessageDO();
            messageDO.setFromId(MindUtils.getUserId());
            messageDO.setToId(IdConstant.superAdmin);
            messageDO.setLinkId(questionDO.getId());
            messageDO.setQuestionId(questionDO.getId());
            messageDO.setType(MessageTypeEnum.SPECIAL_QUESTION_WAIT);
            messageService.save(messageDO);


        }else {
            // 普通提问
            // TODO 敏感词筛查（包括所包含的观点和回答，后面将不再审查）


            questionDO.setStatus(StatusEnum.PASS);
            questionDO.setIsSpecial(0);
            // 保存
            save(questionDO);
            map.put("question",questionDO.getId());
        }

        // 新增所有附带的观点和观点附带的回答
        for (PointAddDTO pointAddDTO : questionAddDTO.getPointAddDTOList()) {
            // 新增观点
            PointDO pointDO = new PointDO();
            BeanUtils.copyProperties(pointAddDTO, pointDO);
            pointDO.setUserId(MindUtils.getUserId());
            pointDO.setQuestionId(questionDO.getId());
            pointDO.setStatus(StatusEnum.PASS);
            pointService.save(pointDO);

            map.put("point",pointDO.getId());

            //新增回答
            AnswerDO answerDO = new AnswerDO();
            BeanUtils.copyProperties(pointAddDTO.getAnswerAddDTO(), answerDO);
            answerDO.setUserId(MindUtils.getUserId());
            answerDO.setStatus(StatusEnum.PASS);
            answerDO.setQuestionId(questionDO.getId());
            answerDO.setPointId(pointDO.getId());
            answerService.save(answerDO);

            map.put("answer",answerDO.getId());

        }
        // 更新用户数据
        UserDataDO userDataDO = userDataService.getById(MindUtils.getUserId());
        userDataDO.setCreateCount(userDataDO.getCreateCount()+1);
        userDataDO.setFollowCount(userDataDO.getFollowCount()+ questionAddDTO.getPointAddDTOList().size());
        userDataService.updateById(userDataDO);

        // 维护mind记录
        mindService.addQuestion(questionDO.getId(),questionDO.getVisibility());

        return map;
    }

    // 用户式删除，根据权限
    @Transactional(rollbackFor=Exception.class)
    public void delete(String id) {
        QuestionDO questionDO = getById(id);
        //判断是否是自己的数据，如果不是则拒绝
        if(!questionDO.getUserId().equals(MindUtils.getUserId())){
            return ;
        }
        // 加精问题不可删除，普通问题没有观点了可以删除
        if (questionDO.getIsSpecial() == 1){
            return ;
        }
        // TODO 判断是否可删除，没观点了

        // 维护mind表
        mindService.deleteMindByLinkId(id);

        // 删除问题
        removeById(id);
    }

    @Transactional(rollbackFor=Exception.class)
    public void updateInfo(QuestionUpdateDTO updateVO) {
        QuestionDO questionDO = getById(updateVO.getId());
        //判断是否是自己的数据
        if(questionDO.getUserId().equals(MindUtils.getUserId())){
            BeanUtils.copyProperties(updateVO, questionDO);
            updateById(questionDO);
        }
    }


    // 要带上观点集合
    public QuestionInfoVO getInfoVO(String id) {
        QuestionDO questionDO = getById(id);
        QuestionInfoVO questionInfoVO = new QuestionInfoVO();
        BeanUtils.copyProperties(questionDO,questionInfoVO);

        questionInfoVO.setIsSpecial(questionDO.getIsSpecial() == 1);
        questionInfoVO.setIsHot(questionDO.getIsHot() == 1);
        questionInfoVO.setIsFollowed(questionUserService.hasFollow(id,MindUtils.getUserId()));
        questionInfoVO.setIsMine(MindUtils.getUserId().equals(questionDO.getUserId()));

        questionInfoVO.setFollowerCount(questionUserService.countFollower(id));
        questionInfoVO.setPointCount(pointService.countByQuestionId(id));
        questionInfoVO.setAnswerCount(answerService.countByQuestionId(id));

        questionInfoVO.setUserInfo(userService.getFollowInfoVO(questionDO.getUserId(),MindUtils.getUserId()));

        return questionInfoVO;
    }

    public PageResult<QuestionListVO> pageOrderByHeat(QuestionQueryDTO questionQuery) {
        //首先更新热度
        updateQuestionsHeat();

        LambdaQueryChainWrapper<QuestionDO> wrapper = lambdaQuery().orderByDesc(QuestionDO::getHeat);

        if(questionQuery.getVisibility() != null){
            if(questionQuery.getVisibility() == 1){
                wrapper.eq(QuestionDO::getVisibility,1);
            }else {
                wrapper.le(QuestionDO::getVisibility,questionQuery.getVisibility());
            }
        }
        if(StringUtils.isNotBlank(questionQuery.getTitle())){
            wrapper.like(QuestionDO::getTitle,questionQuery.getTitle());
        }

        if(questionQuery.getIsSpecial() != null){
            wrapper.eq(QuestionDO::getIsSpecial,questionQuery.getIsSpecial());
        }

        Page<QuestionDO> page = wrapper.page(new Page<>(questionQuery.getPageNow(), questionQuery.getPageSize()));
        if(page.getTotal() == 0){
            return new PageResult<>();
        }
        List<QuestionListVO> list = new ArrayList<>();
        for (QuestionDO record : page.getRecords()) {
            QuestionListVO questionListVO = new QuestionListVO();
            BeanUtils.copyProperties(record, questionListVO);

            questionListVO.setIsSpecial(record.getIsSpecial() == 1);
            questionListVO.setIsMine(record.getUserId().equals(MindUtils.getUserId()));

            questionListVO.setUserInfo(userService.getBasicInfoVO(record.getUserId()));

            list.add(questionListVO);
        }
        return new PageResult<>(page.getTotal(),list);
    }


    // 封装mind
    public QuestionMindListVO getMindListVOByQuestionId(String questionId) {
        QuestionDO questionDO = lambdaQuery()
                .select(QuestionDO::getUserId)
                .eq(QuestionDO::getId, questionId)
                .one();

        // 获取问题提出者的观点id
        String pointId = pointService.lambdaQuery()
                .select(PointDO::getId)
                .eq(PointDO::getQuestionId, questionId)
                .eq(PointDO::getUserId, questionDO.getUserId())
                .last("limit 1").list().get(0).getId();

        // 获取问题提出者的回答id
        String answerId = answerService.lambdaQuery()
                .select(AnswerDO::getId)
                .eq(AnswerDO::getPointId, pointId)
                .eq(AnswerDO::getUserId, questionDO.getUserId())
                .last("limit 1").list().get(0).getId();
        return getMindListVO(questionId,pointId,answerId);
    }

    public QuestionMindListVO getMindListVOByPointId(String pointId) {
        PointDO pointDO = pointService.lambdaQuery()
                .select(PointDO::getUserId,
                        PointDO::getQuestionId)
                .eq(PointDO::getId, pointId)
                .one();

        // 获取观点提出者的回答id
        String answerId = answerService.lambdaQuery()
                .select(AnswerDO::getId)
                .eq(AnswerDO::getPointId, pointId)
                .eq(AnswerDO::getUserId, pointDO.getUserId())
                .last("limit 1")
                .list()
                .get(0)
                .getId();

        return getMindListVO(pointDO.getQuestionId(),pointId,answerId);
    }

    public QuestionMindListVO getMindListVOByAnswerId(String answerId) {
        AnswerDO answerDO = answerService.lambdaQuery()
                .select(AnswerDO::getPointId,
                        AnswerDO::getQuestionId)
                .eq(AnswerDO::getId, answerId)
                .one();
        return getMindListVO(answerDO.getQuestionId(),answerDO.getPointId(),answerId);
    }

    public QuestionMindListVO getMindListVO(String questionId,String pointId,String answerId){
        QuestionDO questionDO = getById(questionId);
        QuestionMindListVO questionMindListVO = new QuestionMindListVO();
        BeanUtils.copyProperties(questionDO, questionMindListVO);
        // 判断是否加精
        questionMindListVO.setIsSpecial(questionDO.getIsSpecial() == 1);
        // 设置用户信息
        questionMindListVO.setUserInfo(userService.getBasicInfoVO(questionDO.getUserId()));
        // 设置观点
        PointDO pointDO = pointService.lambdaQuery().select(PointDO::getKeyword).eq(PointDO::getId,pointId).one();
        questionMindListVO.setPoint(pointDO.getKeyword());
        questionMindListVO.setPointId(pointId);
        // 设置回答
        AnswerDO answerDO = answerService.lambdaQuery().select(AnswerDO::getContent).eq(AnswerDO::getId,answerId).one();
        questionMindListVO.setAnswer(answerDO.getContent());
        questionMindListVO.setAnswerId(answerId);
        return questionMindListVO;
    }


    //更新所有字段的heat值
    @Transactional(rollbackFor=Exception.class)
    public void updateQuestionsHeat(){
        Date now=new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            Date currentDate = sdf.parse(sdf.format(now));
            QueryWrapper<QuestionDO> wrapper = new QueryWrapper<>();
            List<QuestionDO> questionDOList = baseMapper.selectList(wrapper);
            for(QuestionDO questionDO : questionDOList){
                String v = setQuestionHot(questionDO, currentDate);
                questionDO.setHeat(v);
                baseMapper.updateById(questionDO);
            }
        } catch (ParseException e){
            e.printStackTrace();
        }
    }

    //热度排行算法
    public String setQuestionHot(QuestionDO questionDO, Date currentDate) {
        Integer pointNumber = pointService.countByQuestionId(questionDO.getId());
        Integer answerNumber = answerService.countByQuestionId(questionDO.getId());
        Integer followerNumber = questionUserService.getFollowerCountByQuestionId(questionDO.getId());
        Date gmtCreate = questionDO.getGmtCreate();
        float v = MindUtils.differentDaysByMillisecond(gmtCreate, currentDate);
        double heat = (answerNumber*1.5+pointNumber*5+followerNumber*2+1) / Math.pow((v + 2), 1.8);
        return heat+"";
    }


    public List<QuestionHotListVO> listHot() {
        List<QuestionDO> questionDOList = lambdaQuery().eq(QuestionDO::getIsHot, 1).list();
        if(questionDOList == null || questionDOList.size() == 0){
            return new ArrayList<>();
        }

        List<QuestionHotListVO> list = new ArrayList<>();
        for (QuestionDO record : questionDOList) {
            QuestionHotListVO questionListVO = new QuestionHotListVO();
            BeanUtils.copyProperties(record,questionListVO);

            questionListVO.setPoints(pointService.listTwo(record.getId()));
            questionListVO.setFollowerCount(questionUserService.countFollower(record.getId()));
            questionListVO.setPointCount(pointService.countByQuestionId(record.getId()));
            questionListVO.setAnswerCount(answerService.countByQuestionId(record.getId()));

            if(MindUtils.isLogin()){
                questionListVO.setIsFollowed(questionUserService.hasFollow(record.getId(),MindUtils.getUserId()));
            }
            list.add(questionListVO);
        }
        return list;
    }

    public String getQuestionTitle(String questionId) {
        return lambdaQuery().select(QuestionDO::getTitle).eq(QuestionDO::getId,questionId).one().getTitle();
    }

    public boolean isSpecial(String questionId) {
        return lambdaQuery().select(QuestionDO::getIsSpecial).eq(QuestionDO::getId,questionId).one().getIsSpecial() == 1;
    }

    public void updateVisibility(VisibilityUpdateDTO updateDTO) {
        lambdaUpdate().set(QuestionDO::getVisibility,updateDTO.getVisibility())
                .eq(QuestionDO::getId,updateDTO.getId())
                .update();

        mindService.updateVisibilityByLinkId(updateDTO.getId(),updateDTO.getVisibility());
    }
}
